/**
 * MCP Bridged Agent
 * Converts external Markdown-based agents to executable BaseAgent instances
 * using MCP Tool Bridge for tool mapping and execution
 */

import { BaseAgent, AgentContext, AgentResult, AgentCapability } from './base-agent.js';
import { ExternalAgentInfo } from './external-agent-system.js';
import { MCPToolBridge, ToolMapping } from './mcp-tool-bridge.js';

export interface ParsedAgentStep {
  action: string;
  tool?: string;
  parameters?: Record<string, any>;
  description: string;
}

export class MCPBridgedAgent extends BaseAgent {
  private agentInfo: ExternalAgentInfo;
  private toolBridge: MCPToolBridge;
  private parsedSteps: ParsedAgentStep[] = [];
  private instructions: string = '';

  constructor(name: string, agentInfo: ExternalAgentInfo) {
    super(name, '1.0.0');
    this.agentInfo = agentInfo;
    this.toolBridge = new MCPToolBridge();
    this.parseAgentContent();
    this.setupCapabilities();
  }

  private parseAgentContent(): void {
    const content = this.agentInfo.content;

    // Extract instructions (everything after frontmatter)
    const frontmatterMatch = content.match(/^---\s*\n[\s\S]*?\n---\s*\n([\s\S]*)$/);
    this.instructions = frontmatterMatch ? frontmatterMatch[1] : content;

    // Parse tool-specific instructions or action patterns
    this.parsedSteps = this.extractActionSteps(this.instructions);
  }

  private extractActionSteps(instructions: string): ParsedAgentStep[] {
    const steps: ParsedAgentStep[] = [];

    // Look for common patterns in agent instructions
    const lines = instructions.split('\n');
    let currentSection = '';

    for (const line of lines) {
      const trimmed = line.trim();

      // Track current section
      if (trimmed.startsWith('##') || trimmed.startsWith('#')) {
        currentSection = trimmed.replace(/^#+\s*/, '').toLowerCase();
        continue;
      }

      // Extract numbered steps
      const stepMatch = trimmed.match(/^(\d+)\.\s*\*\*([^*]+)\*\*:?\s*(.*)$/);
      if (stepMatch) {
        const [, stepNum, action, description] = stepMatch;
        steps.push({
          action: action.toLowerCase().trim(),
          description: description || trimmed,
          parameters: {}
        });
        continue;
      }

      // Extract bullet points with actions
      const bulletMatch = trimmed.match(/^[-*]\s*\*\*([^*]+)\*\*:?\s*(.*)$/);
      if (bulletMatch) {
        const [, action, description] = bulletMatch;
        steps.push({
          action: action.toLowerCase().trim(),
          description: description || trimmed,
          parameters: {}
        });
        continue;
      }

      // Extract code blocks with tool usage
      if (trimmed.includes('```') && (trimmed.includes('bash') || trimmed.includes('yaml') || trimmed.includes('typescript'))) {
        steps.push({
          action: 'execute_code',
          tool: this.inferToolFromCode(line),
          description: `Execute code block in ${currentSection}`,
          parameters: { code: line, context: currentSection }
        });
      }
    }

    return steps;
  }

  private inferToolFromCode(code: string): string | undefined {
    const codeLower = code.toLowerCase();

    // Tool inference based on code content
    if (codeLower.includes('task:') || codeLower.includes('task ')) return 'Task';
    if (codeLower.includes('glob') || codeLower.includes('find')) return 'Glob';
    if (codeLower.includes('grep') || codeLower.includes('search')) return 'Grep';
    if (codeLower.includes('read') || codeLower.includes('cat')) return 'Read';
    if (codeLower.includes('write') || codeLower.includes('echo')) return 'Write';
    if (codeLower.includes('bash') || codeLower.includes('git')) return 'Bash';

    return undefined;
  }

  private setupCapabilities(): void {
    const capabilities: AgentCapability[] = [];

    // Add capabilities based on metadata
    if (this.agentInfo.metadata.tools) {
      for (const tool of this.agentInfo.metadata.tools) {
        capabilities.push({
          name: tool.toLowerCase(),
          description: `Can use ${tool} tool`,
          examples: [`Using ${tool} for data processing`]
        });
      }
    }

    // Add capabilities based on agent name and description
    const name = this.agentInfo.name.toLowerCase();
    const description = this.agentInfo.metadata.description?.toLowerCase() || '';

    if (name.includes('test') || description.includes('test')) {
      capabilities.push({
        name: 'testing',
        description: 'Execute and analyze test results',
        examples: ['Run test suites', 'Analyze test failures']
      });
    }

    if (name.includes('parallel') || description.includes('parallel')) {
      capabilities.push({
        name: 'parallel-execution',
        description: 'Coordinate parallel execution of tasks',
        examples: ['Manage multiple work streams', 'Synchronize parallel agents']
      });
    }

    if (name.includes('backend') || description.includes('backend')) {
      capabilities.push({
        name: 'backend-development',
        description: 'Design and implement backend systems',
        examples: ['API development', 'Database design']
      });
    }

    if (name.includes('quality') || description.includes('quality')) {
      capabilities.push({
        name: 'quality-assurance',
        description: 'Ensure software quality through testing and validation',
        examples: ['Quality metrics', 'Test strategy design']
      });
    }

    this.capabilities = capabilities;
  }

  async execute(context: AgentContext): Promise<AgentResult> {
    try {
      this.log(`Executing ${this.agentInfo.source} agent: ${this.name}`);

      // Prepare execution context
      const executionContext = {
        ...context,
        agentType: this.agentInfo.source,
        agentMetadata: this.agentInfo.metadata,
        instructions: this.instructions
      };

      // For complex agents like parallel-worker, use special execution logic
      if (this.name === 'parallel-worker') {
        return await this.executeParallelWorker(executionContext);
      }

      // For test agents, use test-specific execution
      if (this.name.includes('test')) {
        return await this.executeTestAgent(executionContext);
      }

      // For development agents, use development-specific execution
      if (this.isDevAgent()) {
        return await this.executeDevAgent(executionContext);
      }

      // Default execution: process instructions step by step
      return await this.executeGenericAgent(executionContext);

    } catch (error: any) {
      this.log(`Execution failed: ${error.message}`, 'error');
      return {
        success: false,
        error: `Agent execution failed: ${error.message}`,
        data: {
          agentName: this.name,
          agentSource: this.agentInfo.source
        }
      };
    }
  }

  private async executeParallelWorker(context: AgentContext): Promise<AgentResult> {
    this.log('Executing parallel worker coordination');

    try {
      // Parallel worker needs to read task analysis and spawn sub-agents
      const tasks = context.tasks || [];
      const results: any[] = [];

      for (const task of tasks) {
        this.log(`Processing task: ${task.id}`);

        // Use Task tool to spawn sub-agents for each work stream
        const subAgentResult = await this.toolBridge.executeTool('Task', {
          description: `Execute task ${task.id}: ${task.description}`,
          subagent_type: 'general-purpose',
          prompt: `You are implementing task ${task.id} in worktree context.

Task: ${task.description}
Working Directory: ${context.workingDirectory || context.projectPath}

Instructions:
1. Implement ONLY the assigned scope
2. Commit changes with format: "Task ${task.id}: {specific change}"
3. Test your changes if applicable

Return summary of what was completed.`
        });

        results.push({
          taskId: task.id,
          result: subAgentResult
        });
      }

      return {
        success: true,
        data: {
          executedTasks: results.length,
          results: results,
          summary: `Parallel execution completed for ${results.length} tasks`
        }
      };

    } catch (error: any) {
      return {
        success: false,
        error: `Parallel worker execution failed: ${error.message}`
      };
    }
  }

  private async executeTestAgent(context: AgentContext): Promise<AgentResult> {
    this.log('Executing test agent');

    try {
      // Test agents typically need to run tests and analyze results
      const testResults = await this.toolBridge.executeTool('Bash', {
        command: 'npm test',
        description: 'Run test suite'
      });

      return {
        success: testResults.success,
        data: {
          testOutput: testResults.data,
          summary: testResults.success ? 'Tests passed' : 'Tests failed',
          testAgent: this.name
        }
      };

    } catch (error: any) {
      return {
        success: false,
        error: `Test execution failed: ${error.message}`
      };
    }
  }

  private async executeDevAgent(context: AgentContext): Promise<AgentResult> {
    this.log('Executing development agent');

    try {
      const tasks = context.tasks || [];
      const results: string[] = [];

      for (const task of tasks) {
        // Development agents typically analyze, design, and implement
        results.push(`Processed task: ${task.id} - ${task.description}`);
      }

      return {
        success: true,
        data: {
          processedTasks: results.length,
          results: results,
          agentType: 'development',
          capabilities: this.capabilities.map(c => c.name)
        }
      };

    } catch (error: any) {
      return {
        success: false,
        error: `Development agent execution failed: ${error.message}`
      };
    }
  }

  private async executeGenericAgent(context: AgentContext): Promise<AgentResult> {
    this.log('Executing generic agent workflow');

    try {
      const results: any[] = [];

      // Execute parsed steps
      for (const step of this.parsedSteps) {
        if (step.tool) {
          const result = await this.toolBridge.executeTool(step.tool, step.parameters || {});
          results.push({
            step: step.action,
            tool: step.tool,
            result: result
          });
        } else {
          // For non-tool steps, just log the action
          results.push({
            step: step.action,
            description: step.description,
            status: 'noted'
          });
        }
      }

      return {
        success: true,
        data: {
          executedSteps: results.length,
          results: results,
          instructions: this.instructions
        }
      };

    } catch (error: any) {
      return {
        success: false,
        error: `Generic agent execution failed: ${error.message}`
      };
    }
  }

  private isDevAgent(): boolean {
    const name = this.name.toLowerCase();
    const devKeywords = ['architect', 'engineer', 'developer', 'expert'];
    return devKeywords.some(keyword => name.includes(keyword));
  }

  getAgentInfo(): ExternalAgentInfo {
    return this.agentInfo;
  }

  getInstructions(): string {
    return this.instructions;
  }

  getParsedSteps(): ParsedAgentStep[] {
    return [...this.parsedSteps];
  }
}